package com.cloudkinto.service.order;

import cn.afterturn.easypoi.excel.entity.ExportParams;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.cloudkinto.common.DicBusinessItemConstant;
import com.cloudkinto.common.common.DateUtils;
import com.cloudkinto.common.constant.SysConstant;
import com.cloudkinto.common.exception.BizException;
import com.cloudkinto.common.utils.ExcelUtils;
import com.cloudkinto.common.utils.TimeUtils;
import com.cloudkinto.common.utils.XmlUtils;
import com.cloudkinto.common.web.PageResult;
import com.cloudkinto.common.web.SingleResult;
import com.cloudkinto.dao.*;
import com.cloudkinto.entity.*;
import com.cloudkinto.service.company.CompanyService;
import com.cloudkinto.service.finance.CompanyAccountService;
import com.cloudkinto.service.operate.OperateRecordService;
import com.cloudkinto.service.operate.vo.OperateRes;
import com.cloudkinto.service.order.vo.yahoo.*;
import com.cloudkinto.service.orderoutput.OrderOutputService;
import com.cloudkinto.service.orderoutput.vo.OrderOutputAddReq;
import com.cloudkinto.service.orderoutput.vo.OrderOutputPackageAddReq;
import com.cloudkinto.service.orderoutput.vo.OrderOutputProductAddReq;
import com.cloudkinto.service.product.ProductCombinationService;
import com.cloudkinto.service.product.ProductInfoService;
import com.cloudkinto.service.region.JpRegionService;
import com.cloudkinto.service.shipprice.ShipPriceService;
import com.cloudkinto.service.shop.ShopService;
import com.cloudkinto.service.user.UserService;
import com.cloudkinto.utils.YahooUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.poi.ss.usermodel.IndexedColors;
import org.jdom2.JDOMException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * <p>
 * service实现类
 * </p>
 *
 * @author huajiyu
 * @since 2022-07-11
 */
@Service
@Transactional(rollbackFor = Exception.class)//事务回滚
public class OrderYahooServiceImpl extends ServiceImpl<OrderYahooDao, OrderYahooDo> implements OrderYahooService {
    @Autowired
    private OrderYahooDao dao;
    @Autowired
    private RedisTemplate redisTemplate;
    @Autowired
    private ShopDao shopDao;
    @Autowired
    private RabbitTemplate rabbitTemplate;
    @Autowired
    private ShopService shopService;
    @Autowired
    private UserService userService;
    private final String redirectUri = "https://erp.cangsoft.com/shopAuthorization";
    private final String yahooScope = "openid profile email address ";

    private final String YAHOOACCESSTOKEN_USER = "YAHOOACCESSTOKEN_USER_";//用户访问令牌(短期)(1小时)
    private final String YAHOOREFRESH_TOKEN_USER = "YAHOOREFRESH_TOKEN_USER_";//用户刷新令牌(长期)(4周)
    private String AUTHORIZESTATEKEY = "yahoo_authorize_state_";
    private final Logger logger = LoggerFactory.getLogger(getClass());
    private final String orderYahooSign = "orderYahooSignList";
    @Autowired
    private OrderYahooItemDao itemDao;
    @Autowired
    private OperateRecordService operateRecordDao;
    @Autowired
    private OrderOutputService orderOutputService;
    @Autowired
    private ProductInfoDao productInfoDao;
    @Autowired
    private StorageDao storageDao;
    @Autowired
    private CompanyAccountService mAccountService;
    @Autowired
    private ShipPriceService shipPriceService;
    @Autowired
    private JpRegionService mRegionService;
    @Autowired
    private StockRecordDao stockDao;
    @Autowired
    private ProductInfoService productInfoService;
    @Autowired
    private ProductCombinationService productCombinationService;
    @Autowired
    private CompanyService companyService;

    @Override
    public SingleResult addInit() {
        return SingleResult.success("");
    }

    @Override
    public Object add(Object req, Long userId) {
        OrderYahooDo entityDo = new OrderYahooDo();
        BeanUtils.copyProperties(req, entityDo);
        handlerAddBefore(entityDo, userId);
        dao.insert(entityDo);
        return handlerAddAfter(entityDo);
    }

    //新增校验
    private void addCheck(Object req) {

    }

    //做新增之前要执行的业务定制处理
    private void handlerAddBefore(OrderYahooDo entityDo, Long userId) {

    }

    //将新增的do转换成要返回的实体
    private Object handlerAddAfter(OrderYahooDo entityDo) {
        Object res = new Object();
        BeanUtils.copyProperties(entityDo, res);
        return res;
    }

    @Override
    public SingleResult updateInit(Long id) {
        return SingleResult.success("");
    }

    @Override
    public Object update(Object req, Long userId) {
        /*OrderYahooDo entityDo = dao.selectById(req.getId());
        BeanUtils.copyProperties(req, entityDo);
        handlerUpdateBefore(entityDo, userId);
        dao.updateById(entityDo);
        return handlerUpdateAfter(entityDo);*/
        return null;
    }

    //编辑校验
    private void updateCheck(Object req) {

    }

    //做修改之前要执行的业务定制处理
    private void handlerUpdateBefore(OrderYahooDo entityDo, Long userId) {

    }

    //做修改之后要执行的业务定制处理
    private Object handlerUpdateAfter(OrderYahooDo entityDo) {
        Object res = new Object();
        BeanUtils.copyProperties(entityDo, res);
        return res;
    }

    @Override
    public int delete(Long id, Long userId) {
        OrderYahooDo entityDo = dao.selectById(id);
        handlerDeleteBefore(entityDo, userId);
        return dao.deleteById(id);
    }

    //做删除之前要执行的业务定制处理
    private void handlerDeleteBefore(OrderYahooDo entityDo, Long userId) {

    }

    @Override
    public OrderYahooDetailRes detail(Long id) {
        OrderYahooDo entityDo = dao.selectById(id);
        return handlerDetailAfter(entityDo);
    }

    //查询明细之后要执行的业务定制处理
    private OrderYahooDetailRes handlerDetailAfter(OrderYahooDo entityDo) {
        OrderYahooDetailRes res = new OrderYahooDetailRes();
        BeanUtils.copyProperties(entityDo, res);
        ShopDo shopDo = shopDao.selectById(entityDo.getShopId());
        if (shopDo != null) res.setShopName(shopDo.getShopName());
        res.setSettleStatus(getSettleStatus(entityDo.getSettleStatus()));
        res.setShipName(entityDo.getShipFirstName() + " " + entityDo.getShipLastName());
        LambdaQueryWrapper<OrderYahooItemDo> itemDoLambdaQueryWrapper = new LambdaQueryWrapper<>();
        itemDoLambdaQueryWrapper.eq(OrderYahooItemDo::getOrderId, entityDo.getId());
        List<OrderYahooItemDo> itemDoList = itemDao.selectList(itemDoLambdaQueryWrapper);
        for (OrderYahooItemDo orderYahooItemDo : itemDoList) {
            OrderYahooItemDetail detail = new OrderYahooItemDetail();
            detail.setQuantity(orderYahooItemDo.getQuantity());
            detail.setItemId(orderYahooItemDo.getItemId());
            detail.setTitle(orderYahooItemDo.getTitle());
            if (res.getItem() == null) res.setItem(new ArrayList<>());
            res.getItem().add(detail);
        }
        List<OperateRes> operateResList = operateRecordDao.getOperateList(res.getId(),5);
        res.setOperateResList(operateResList);
        return res;
    }

    @Override
    public SingleResult pageInit() {
        Map map = new HashMap();
        map.put("companyList", companyService.tree());
        return SingleResult.success(map);
    }

    @Override
    public List<OrderYahooDoPageEntity> getList(Map<String, String> map) {
        QueryWrapper<OrderYahooDo> wrapper = queryBuild(map);
        List<OrderYahooDo> list = this.list(wrapper);
        List<OrderYahooDoPageEntity> result = handlerListAfter(list);
        return result;
    }

    @Override
    public PageResult getListPage(Map<String, String> map) {
        QueryWrapper<OrderYahooDo> wrapper = queryBuild(map);
        IPage<OrderYahooDo> page = pageInit(map);
        page = this.page(page, wrapper);
        List<OrderYahooDoPageEntity> resList = handlerListAfter(page.getRecords());
        PageResult result = new PageResult(resList, (int) page.getCurrent(), (int) page.getSize(), (int) page.getTotal(), (int) page.getPages());
        return result;
    }

    //查询分页列表之后对列表数据的处理
    private List<OrderYahooDoPageEntity> handlerListAfter(List<OrderYahooDo> list) {
        List<OrderYahooDoPageEntity> result = new ArrayList<>();
        result = list.stream().map(orderYahooDo -> {
            OrderYahooDoPageEntity orderYahooDoPage = new OrderYahooDoPageEntity();
            BeanUtils.copyProperties(orderYahooDo, orderYahooDoPage);
            ShopDo shopDo = shopDao.selectById(orderYahooDo.getShopId());
            if (shopDo != null) orderYahooDoPage.setShopName(shopDo.getShopName());
            if (StringUtils.isNotBlank(orderYahooDo.getPayKind()))
                orderYahooDoPage.setPayKind(getPayKind(orderYahooDo.getPayKind()));
            if (StringUtils.isNotBlank(orderYahooDo.getSettleStatus()))
                orderYahooDoPage.setSettleStatus(getSettleStatus(orderYahooDo.getSettleStatus()));
            orderYahooDoPage.setShipName(orderYahooDo.getShipLastName() + " " + orderYahooDo.getShipFirstName());
            LambdaQueryWrapper<OrderYahooItemDo> itemDoLambdaQueryWrapper = new LambdaQueryWrapper<>();
            itemDoLambdaQueryWrapper.eq(OrderYahooItemDo::getOrderId, orderYahooDo.getId());
            List<OrderYahooItemDo> itemDoList = itemDao.selectList(itemDoLambdaQueryWrapper);
            String sku = itemDoList.stream().map(OrderYahooItemDo::getItemId).collect(Collectors.joining(","));
            orderYahooDoPage.setSku(sku);
            return orderYahooDoPage;
        }).collect(Collectors.toList());
        return result;
    }

    private String getSettleStatus(String settleStatus) {
        //1 : 決済申込
        //2 : 支払待ち
        //3 : 支払完了
        //4 : 入金待ち
        //5 : 決済完了
        //6 : キャンセル
        //7 : 返金
        //8 : 有効期限切れ
        //9 : 決済申込中
        //10 : オーソリエラー
        //11 : 売上取消
        //12 : Suicaアドレスエラー
        switch (settleStatus) {
            case "1":
                return "決済申込";
            case "2":
                return "支払待ち";
            case "3":
                return "支払完了";
            case "4":
                return "入金待ち";
            case "5":
                return "決済完了";
            case "6":
                return "キャンセル";
            case "7":
                return "返金";
            case "8":
                return "有効期限切れ";
            case "9":
                return "決済申込中";
            case "10":
                return "オーソリエラー";
            case "11":
                return "売上取消";
            case "12":
                return "Suicaアドレスエラー";
        }
        return null;
    }

    private String getPayKind(String payKind) {
        //0 : カード
        //1 : ネットバンキング
        //2 : キャリア決済
        //3 : 振込
        //4 : 代引
        //5 : コンビニ
        //6 : 電子マネー
        //7 : その他
        switch (payKind) {
            case "0":
                return "カード";
            case "1":
                return "ネットバンキング";
            case "2":
                return "キャリア決済";
            case "3":
                return "振込";
            case "4":
                return "代引";
            case "5":
                return "コンビニ";
            case "6":
                return "電子マネー";
            case "7":
                return "その他";
        }
        return null;
    }

    private IPage<OrderYahooDo> pageInit(Map<String, String> map) {
        IPage<OrderYahooDo> page = new Page();
        page.setSize(StringUtils.isNotBlank(map.get("pageSize")) ? Long.parseLong(map.get("pageSize")) : 10);
        page.setCurrent(StringUtils.isNotBlank(map.get("current")) ? Long.parseLong(map.get("current")) : 1);
        return page;
    }

    private QueryWrapper<OrderYahooDo> queryBuild(Map<String, String> map) {
        QueryWrapper<OrderYahooDo> wrapper = new QueryWrapper<>();
        if (org.apache.commons.lang.StringUtils.isNotBlank(map.get("keyword"))) {
            wrapper.or(orderRakutenDoQueryWrapper -> {
                orderRakutenDoQueryWrapper.like("order_id", map.get("keyword").trim()).or();
                orderRakutenDoQueryWrapper.like("ship_first_name", map.get("keyword").trim()).or();
                orderRakutenDoQueryWrapper.like("ship_last_name", map.get("keyword").trim()).or();
                orderRakutenDoQueryWrapper.like("system_memo", map.get("keyword").trim()).or();
                orderRakutenDoQueryWrapper.like("ship_phone_number", map.get("keyword").trim()).or();
            });
        }
        if (map.containsKey("isSend")) wrapper.eq("is_send_out", map.get("isSend"));
        if (map.containsKey("orderStatus")) wrapper.eq("order_status", map.get("orderStatus"));
        if (map.containsKey("payStatus")) wrapper.eq("pay_status", map.get("payStatus"));
        if (map.containsKey("shipStatus")) wrapper.eq("ship_status", map.get("shipStatus"));
        if (map.containsKey("shopId")) wrapper.eq("shop_id", map.get("shopId"));
        if (map.containsKey("companyId")) wrapper.eq("company_id", map.get("companyId"));
        if ("0".equals(map.get("dateType"))) {
            if (org.apache.commons.lang.StringUtils.isNotBlank(map.get("dateEnd"))) {
                String date = TimeUtils.formatDate(TimeUtils.getDateAdd(TimeUtils.parseDate(map.get("dateEnd")), 1));
                wrapper.lt("order_time", date);
            }
            if (org.apache.commons.lang.StringUtils.isNotBlank(map.get("dateStart")))
                wrapper.gt("order_time", map.get("dateStart"));
        } else {//更新时间
            if (org.apache.commons.lang.StringUtils.isNotBlank(map.get("dateEnd"))) {
                String date = TimeUtils.formatDate(TimeUtils.getDateAdd(TimeUtils.parseDate(map.get("dateEnd")), 1));
                wrapper.lt("last_update_time", date);
            }
            if (org.apache.commons.lang.StringUtils.isNotBlank(map.get("dateStart")))
                wrapper.gt("last_update_time", map.get("dateStart"));
        }
        wrapper.orderByDesc("order_time");
        return wrapper;
    }

    @Override
    public Map<String, Object> getYahooUserInfoApi(Long shopId) {
        String body = null;
        Map param = new HashMap<>();
//        param.put("callback", "success");//如果指定了 则以 Content-Type: text/javascript 形式返回响应。
        try {
            body = YahooUtils.yahooDoGet("https://userinfo.yahooapis.jp/yconnect/v2/attribute", getYahooUserAccessToken(shopId), param);
        } catch (Exception e) {
            e.printStackTrace();
        }
        Map<String, Object> result = new HashMap<>();
        if (StringUtils.isBlank(body)) {
            result.put("code", "FAIL");
            result.put("msg", "Yahoo获取用户信息api 连接超时");
            return result;
        }
        JSONObject jsonObject = JSONObject.parseObject(body);
        if (StringUtils.isNotBlank(jsonObject.getString("error_description"))) {
            result.put("code", "FAIL");
            result.put("msg", jsonObject.getString("error_description"));
            return result;
        } else {
            //获取成功 保存
            YahooUserInfo userInfo = JSONObject.parseObject(body, YahooUserInfo.class);
            ShopDo shopDo = shopDao.selectById(shopId);
            if (shopDo != null) {
                shopDo.setYahooSellerId(userInfo.getSub());
                shopDao.updateById(shopDo);
            } else {
                log.error("Yahoo getYahooUserInfoApi api 没有对应店铺,店铺id: " + shopId);
            }
            result.put("code", "SUCCESS");
        }
        return result;
    }


    public String getYahooOrderListParam(int Result, int Start, Date OrderTimeFrom, Date OrderTimeTo, String orderId, String Field, String sellerId) {
        if (OrderTimeFrom == null || OrderTimeTo == null) {
            OrderTimeTo = TimeUtils.formatDateToDate(new Date(), "yyyyMMddHHmmss", "Asia/Tokyo");//乐天店铺转成日本时间
            OrderTimeFrom = DateUtils.passingDate(OrderTimeTo, -3);
        } else {
            OrderTimeTo = TimeUtils.formatDateToDate(OrderTimeTo, "yyyyMMddHHmmss", "Asia/Tokyo");
            OrderTimeFrom = TimeUtils.formatDateToDate(OrderTimeFrom, "yyyyMMddHHmmss", "Asia/Tokyo");
        }
        String from = DateUtils.dateFormatToString(OrderTimeFrom, "yyyyMMddHHmmss").replace(" ", "T");
        String to = DateUtils.dateFormatToString(OrderTimeTo, "yyyyMMddHHmmss").replace(" ", "T");

        StringBuilder builder = new StringBuilder("<Req><Search><Result>");
        builder.append(Result).append("</Result><Start>").append(Start).append("</Start>").append("<Sort>+order_time</Sort>");
        builder.append("<Condition>");
        if (StringUtils.isNotBlank(orderId)) {
            builder.append("<OrderId>").append(orderId).append("</OrderId>");
        } else {
            builder.append("<OrderTimeFrom>").append(from).append("</OrderTimeFrom><OrderTimeTo>").append(to).append("</OrderTimeTo>");
        }
        builder.append("</Condition>").append("<Field>").append(Field).append("</Field></Search><SellerId>").append(sellerId).append("</SellerId></Req>");
        return builder.toString();
    }

    @Override
    public void exportExcel(Map<String, String> map, OrderYahooExcelReq req, HttpServletResponse response) throws IOException {
        List<OrderYahooDo> OrderYahooDoList = null;
        if (CollectionUtils.isEmpty(req.getIds())) {
            QueryWrapper<OrderYahooDo> wrapper = queryBuild(map);
            OrderYahooDoList = this.baseMapper.selectList(wrapper);
        } else {
            LambdaQueryWrapper<OrderYahooDo> wrapper = new LambdaQueryWrapper<>();
            wrapper.in(OrderYahooDo::getId, req.getIds())
                    .orderByDesc(OrderYahooDo::getCreateTime);
            OrderYahooDoList = this.baseMapper.selectList(wrapper);
        }
        if (OrderYahooDoList.size() > 1000) {
            response.setStatus(500);
            throw new BizException(SysConstant.File_Export_ToMuch, 1000);
        }
        List<OrderYahooExcelExportVo> excelExportVoList = new ArrayList<>();

        if (!CollectionUtils.isEmpty(OrderYahooDoList)) {
            for (OrderYahooDo rakutenDo : OrderYahooDoList) {
                OrderYahooExcelExportVo excelExportVo = new OrderYahooExcelExportVo();
                BeanUtils.copyProperties(rakutenDo, excelExportVo);

                LambdaQueryWrapper<OrderYahooItemDo> packageDoLambdaQueryWrapper = new LambdaQueryWrapper<>();
                packageDoLambdaQueryWrapper.eq(OrderYahooItemDo::getOrderId, rakutenDo.getId());
                List<OrderYahooItemDo> productDoList = itemDao.selectList(packageDoLambdaQueryWrapper);
                if (!CollectionUtils.isEmpty(productDoList)) {
                    List<OrderYahooItemExcelExportVo> productExcelExportVoList = new ArrayList<>();
                    for (OrderYahooItemDo productDo : productDoList) {
                        OrderYahooItemExcelExportVo productExcelExportVo = new OrderYahooItemExcelExportVo();
                        BeanUtils.copyProperties(productDo, productExcelExportVo);
                        productExcelExportVoList.add(productExcelExportVo);
                    }
                    excelExportVo.setItems(productExcelExportVoList);
                }
                excelExportVoList.add(excelExportVo);
            }
        }
        ExportParams exportParams = new ExportParams();
        exportParams.setCreateHeadRows(true);
        exportParams.setHeaderColor(IndexedColors.YELLOW.getIndex());
        ExcelUtils.exportExcel(excelExportVoList, OrderYahooExcelExportVo.class, "yahoo订单", exportParams, response);
    }

    /**
     * 定时同步订单 发射器
     *
     * @param type
     */
    @Override
    public void timingSyncYahooOrder(String type) {
        List<ShopDo> list = shopDao.selectList(new LambdaQueryWrapper<ShopDo>()
                .isNotNull(ShopDo::getYahooRefreshToken));

        for (ShopDo shopDo : list) {
            if (StringUtils.isBlank(shopDo.getYahooRefreshToken())) {//
                continue;
            }
            Map<String, String> map = new HashMap<>();
            map.put("shopName", shopDo.getShopName());
            map.put("type", type);
            map.put("shopId", shopDo.getId() + "");

            String end = TimeUtils.formatDate(new Date(), "yyyy-MM-dd hh:mm:ss");
            String before;
            if ("all".equals(type)) {
                //同步近7天的订单(创建时间)
                before = TimeUtils.formatDate(DateUtils.passingDate(new Date(), -7), "yyyy-MM-dd HH:mm:ss");
            } else {
                //日常更新 同步最近1 小时 的订单
                before = TimeUtils.formatDate(DateUtils.passingDateHour(new Date(), -1), "yyyy-MM-dd HH:mm:ss");
            }
            map.put("orderTimeTo", end);
            map.put("orderTimeFrom", before);
//            rabbitTemplate.convertAndSend("yahoo.syncYahooOrder", JSON.toJSONString(map));
            getYahooOrderList(shopDo.getId(), map);

        }
    }

    /**
     * Yahoo用户刷新令牌 换取 用户访问令牌
     *
     * @return
     */
    @Override
    public String getYahooUserAccessToken(Long shopId) {
        Object accessToken = redisTemplate.opsForValue().get(YAHOOACCESSTOKEN_USER + shopId);
        if (accessToken != null) {
            return accessToken.toString();
        }
        //accessToken过期， 用refresh_token 换取 accessToken过期
        Object refresh_token = redisTemplate.opsForValue().get(YAHOOREFRESH_TOKEN_USER + shopId);
        ShopDo shopDo = shopDao.selectById(shopId);
        if (shopDo == null) {
            return "";
        }
        if (refresh_token == null && org.apache.commons.lang3.StringUtils.isBlank(shopDo.getYahooRefreshToken())) {//刷新令牌也过期了
            if (org.apache.commons.lang3.StringUtils.isBlank(shopDo.getYahooRefreshToken())) {
                return "";
            }
            LambdaUpdateWrapper<ShopDo> updateWrapper = new LambdaUpdateWrapper<>();
            updateWrapper.set(ShopDo::getYahooRefreshToken, null);
            updateWrapper.eq(ShopDo::getId, shopId);
            shopService.update(updateWrapper);
            log.debug("Yahoo 店铺:" + (shopDo != null ? shopDo.getShopName() : "") + "授权令牌过期，请重新授权");
            return "";
            //throw new BizException("Ebay 店铺:"+ (shopDo != null ? shopDo.getShopName() : "") +"授权令牌过期，请重新授权");
        }
        if (refresh_token == null) {
            refresh_token = shopDo.getYahooRefreshToken();
        }
        //refresh_token 含有特殊符号 需要转义一下 v^1.1#i^1#f^0#p^3#I^3#r^1#t^Ul4xMF83OkE2NUZFMTBENUZDOERBRkZEQUNFQjMxRTFBNjg3NzNFXzJfMSNFXjEyODQ=
        refresh_token = org.apache.commons.lang3.StringUtils.replace(refresh_token.toString(), "#", "%23");
        String body = null;
        Map paramMap = new HashMap<>();
//        grant_type=authorization_code&code=" + code + "&redirect_uri=" + redirectUri
        paramMap.put("grant_type", "refresh_token");
        paramMap.put("refresh_token", refresh_token);
        try {
            body = YahooUtils.yahooDoPost("https://auth.login.yahoo.co.jp/yconnect/v2/token", paramMap);
            //{"error":"invalid_grant","error_description":"the provided authorization refresh token is invalid or was issued to another client"}
        } catch (Exception e) {
            e.printStackTrace();
        }
        if (org.apache.commons.lang3.StringUtils.isBlank(body)) {
            throw new BizException(SysConstant.Error_Connect_Timeout);
        }
        JSONObject jsonObject = JSONObject.parseObject(body);
        String access_token = jsonObject.getString("access_token");
        if (org.apache.commons.lang3.StringUtils.isBlank(access_token)) {
            String error = jsonObject.getString("error_description");
            if (error.contains("the provided authorization refresh token is invalid or was issued to another client")) {//todo 验证 返回值
                //刷新令牌过期，去更改店铺的授权状态 已过期 todo rabbitmq去做
                LambdaUpdateWrapper<ShopDo> updateWrapper = new LambdaUpdateWrapper<>();
                updateWrapper.set(ShopDo::getYahooRefreshToken, null);
                updateWrapper.eq(ShopDo::getId, shopId);
                shopService.update(updateWrapper);
            }
            log.debug(org.apache.commons.lang3.StringUtils.isBlank(error) ? "获取用户访问令牌失败" : (shopDo != null ? "Yahoo店铺 " + shopDo.getShopName() + ":" : "") + error);
            return "";
            //throw new BizException(StringUtils.isBlank(error) ? "获取用户访问令牌失败" : (shopDo != null ? "Yahoo店铺 "+shopDo.getShopName()+":" : "")+error);
        }
        int expires_in = jsonObject.getInteger("expires_in");
        String token_type = jsonObject.getString("token_type");// User Access Token
        redisTemplate.opsForValue().set(YAHOOACCESSTOKEN_USER + shopId, access_token, expires_in - 30, TimeUnit.SECONDS);
        return access_token;
    }


    @Override
    public void updateOrderSendOut(String orderNo) {
        dao.updateOrderSendOut(orderNo);
    }

    @Override
    public void updateOrderUploadExpress(String orderNo) {
        dao.updateOrderUploadExpress(orderNo);
    }

    @Override
    public List<String> queryByShopIdAndNoUploadExpress(Long id, String currentDateFormat, String currentDateFormat1) {
        return dao.queryByShopIdAndNoUploadExpress(id, currentDateFormat, currentDateFormat1);
    }

    @Override
    public void syncYahooOrder(Map<String, String> map, int count) {
        String type = map.get("type");
        Long shopId = Long.parseLong(map.get("shopId"));
        String shopName = map.get("shopName");
        try {
            this.getYahooOrderList(shopId, map);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    @Override
    public List<Map> ordersyncInit(Long currentUserId, Long companyId) {
        List<Map> shopList = new ArrayList<>();
        UserDo userDo = userService.getById(currentUserId);
        if (userDo == null) {
            throw new BizException(SysConstant.User_NotExist);
        }
        LambdaQueryWrapper<ShopDo> shopWrapper = new LambdaQueryWrapper();
        if (userDo.getShopId() != null) shopWrapper.eq(ShopDo::getId, userDo.getShopId());
        if (companyId != null)
            shopWrapper.eq(ShopDo::getCompanyId, companyId);
        shopWrapper.isNotNull(ShopDo::getYahooRefreshToken);
        shopWrapper.isNotNull(ShopDo::getYahooSellerId);
        List<ShopDo> shopDoList = shopDao.selectList(shopWrapper);
        if (!CollectionUtils.isEmpty(shopDoList)) {
            for (ShopDo shopDo : shopDoList) {
                Map shopMap = new HashMap();
                shopMap.put("id", shopDo.getId());
                shopMap.put("value", shopDo.getShopName());
                shopList.add(shopMap);
            }
        }
        return shopList;
    }

    @Override
    public SingleResult queryOrder2SendOut(String[] orderids, Long currentUserId, boolean isAuto, Long companyId) {
        //校验余额是否不足
        if (!mAccountService.getIsDue(companyId)) {
            throw new BizException(SysConstant.User_Error_Arrears);
        }
        List<String> failOrders = new ArrayList<>();
        List<OrderOutputAddReq> resList = new ArrayList<>();
        for (String orderid : orderids) {
            List<OrderOutputAddReq> outputAddReqs = new ArrayList<>();
            try {
                outputAddReqs = sendOutOrder(orderid, currentUserId, isAuto);
            } catch (BizException e) {
                e.printStackTrace();
                failOrders.add(e.getMessage());
            }
            if (outputAddReqs.size() < 1) continue;
            resList.addAll(outputAddReqs);
//            Session session = mailService.initMailSession();
//            Transport transport = mailService.initMailTransport(session);
            operateRecordDao.operateAddRecord(SysConstant.OPERATE_CLICK_SEND,Long.parseLong(orderid),currentUserId,5);
//            operateRecord("点击发货", Long.parseLong(orderid), currentUserId);
        }
//        List<String> failOrders = new ArrayList<>();
        if (isAuto) {
            sendOutMatch(resList, currentUserId, companyId);
        }
        for (OrderOutputAddReq outputAddReq : resList) {
            StringBuilder sku = new StringBuilder();
            int cout = 0;
            for (OrderOutputProductAddReq orderOutputProductAddReq : outputAddReq.getPackageList().get(0).getProductList()) {
                cout = cout + orderOutputProductAddReq.getCount();
                if (org.apache.commons.lang3.StringUtils.isNotBlank(sku)) {
                    sku.append(",");
                }
                sku.append(productInfoService.getById(orderOutputProductAddReq.getProductId()).getCommoditySku());
            }
            outputAddReq.setSku(sku.toString());
            outputAddReq.setCount(cout);
        }
        Map map = new HashMap();
        map.put("orderList", resList);
        map.put("failedList", failOrders);
        map.put("storageList", storageDao.selectList(null));
        return SingleResult.success(map);
    }

    private List<OrderOutputAddReq> sendOutOrder(String orderid, Long currentUserId, boolean isAuto) {
        List<OrderOutputAddReq> resList = new ArrayList<>();
        OrderYahooDo orderYahooDo = this.baseMapper.selectById(orderid);
        if (orderYahooDo == null) {
            throw new BizException(SysConstant.OrderYahoo_NotExist_OrderId,orderid);
        }
        if ("Canceled".equals(orderYahooDo.getOrderStatus()))
            throw new BizException(SysConstant.OrderYahoo_Canceled_OrderId,orderYahooDo.getOrderId());
        LambdaQueryWrapper<OrderYahooItemDo> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(OrderYahooItemDo::getOrderId, orderid);
        List<OrderYahooItemDo> itemsDoList1 = itemDao.selectList(wrapper);
        List<OrderOutputProductAddReq> itemAddReqList = new ArrayList<>();
        //处理原产品信息   + ，组合产品情况
        for (OrderYahooItemDo productDo : itemsDoList1) {
            if (productDo.getItemId().contains("+")) {
                for (String sku : productDo.getItemId().split("\\+")) {
                    OrderOutputProductAddReq productDo1 = new OrderOutputProductAddReq();
                    productDo1.setProductId(productInfoService.getProductId(sku, orderYahooDo.getCompanyId()));
                    productDo1.setCommoditySku(sku);
                    productDo1.setCount(productDo.getQuantity());
                    itemAddReqList.add(productDo1);
                }
            } else {
                ProductInfoDo productInfoDo = productInfoService.getProductDo(productDo.getItemId(), orderYahooDo.getCompanyId());
                if (productInfoDo.getTypeOfProduct().equals(SysConstant.COMMON_PRODUCT)) {
                    OrderOutputProductAddReq productDo1 = new OrderOutputProductAddReq();
                    productDo1.setProductId(productInfoDo.getId());
                    productDo1.setCommoditySku(productInfoDo.getCommoditySku());
                    productDo1.setCount(productDo.getQuantity());
                    itemAddReqList.add(productDo1);
                } else {
                    LambdaQueryWrapper<ProductCombinationDo> productCombinationWrapper = new LambdaQueryWrapper<>();
                    productCombinationWrapper.eq(ProductCombinationDo::getParentId, productInfoDo.getId());
                    List<ProductCombinationDo> productCombinationDoList = productCombinationService.getBaseMapper().selectList(productCombinationWrapper);
                    for (ProductCombinationDo productCombinationDo : productCombinationDoList) {
                        OrderOutputProductAddReq productDo1 = new OrderOutputProductAddReq();
                        ProductInfoDo productInfoDo1 = productInfoService.getById(productCombinationDo.getChildId());
                        if (productInfoDo1 == null) continue;
                        productDo1.setProductId(productCombinationDo.getChildId());
                        productDo1.setCommoditySku(productInfoDo1.getCommoditySku());
                        productDo1.setCount(productCombinationDo.getCount());
                        itemAddReqList.add(productDo1);
                    }
                }
            }
        }
        OrderOutputAddReq res = new OrderOutputAddReq();
        if (orderYahooDo.getCompanyId() == 221) {
            if (orderYahooDo.getShipMethod().equals("postage5"))
                res.setTrackId(DicBusinessItemConstant.yamatoExpress);
        }
//        if (StringUtils.isNotBlank(orderYahooDo.get()))
//            res.setCod((int) Double.parseDouble(orderYahooDo.getPaymentCod()));
        res.setPlatformNumber("yahoo");
        res.setPlatformNumber(orderYahooDo.getId()+"");
        res.setSendDate(new Date());
        res.setShopId(orderYahooDo.getShopId());
        res.setCompanyId(orderYahooDo.getCompanyId());
        res.setOrderNo(orderYahooDo.getOrderId());
        res.setReceiverName(orderYahooDo.getShipLastName() + " " + orderYahooDo.getShipFirstName());
        res.setTelPhone(orderYahooDo.getShipPhoneNumber());
        res.setPostCode(orderYahooDo.getShipZipCode());
        res.setArea(orderYahooDo.getShipPrefecture());
        if (StringUtils.isNotBlank(orderYahooDo.getShipCity())) {
            res.setAddress(orderYahooDo.getShipCity() + getAddress(orderYahooDo.getShipAddress1(), orderYahooDo.getShipAddress2()));
        } else {
            res.setAddress(getAddress(orderYahooDo.getShipAddress1(), orderYahooDo.getShipAddress2()));
        }
        if (orderYahooDo.getShipRequestDate() != null) {
            res.setDeliveryDate(TimeUtils.formatDate(orderYahooDo.getShipRequestDate()));
        }
        if (orderYahooDo.getShipRequestTime() != null) {
            res.setDeliveryTime(orderYahooDo.getShipRequestTime().replaceAll(":00", ""));
        }
        long storageId = 0L;
        long stateId = 0;
        //item
        List<OrderOutputProductAddReq> orderOutputProductDetailList = new ArrayList<>();
        List<OrderOutputProductAddReq> failedItems = new ArrayList<>();
        if (!CollectionUtils.isEmpty(itemAddReqList)) {
            double[] size = new double[4];
            double shipPirce = 99999D;
            //先看都有货的仓库
            LambdaQueryWrapper<StorageDo> lambdaQueryWrapper1 = new LambdaQueryWrapper<>();
            lambdaQueryWrapper1.eq(StorageDo::getSupportShip, 1);
            List<StorageDo> firstStorages = storageDao.selectList(lambdaQueryWrapper1);
            kk:
            for (StorageDo storageDo : firstStorages) {
                for (OrderOutputProductAddReq itemsDo : itemAddReqList) {

                    Long productId = itemsDo.getProductId();
                    if (productId == null) {
                        throw new BizException(SysConstant.OrderYahoo_Product_Notfound, orderYahooDo.getOrderId(), itemsDo.getCommoditySku());
                    }
                    LambdaQueryWrapper<StockRecordDo> wrapper1 = new LambdaQueryWrapper<>();
                    wrapper1.eq(StockRecordDo::getShopId, res.getShopId()).eq(StockRecordDo::getProductInfoId, productId).eq(StockRecordDo::getStorageId, storageDo.getId());
                    StockRecordDo stockRecordDo = stockDao.selectOne(wrapper1);
                    if (stockRecordDo == null) {
                        continue kk;
                    }
                    int noDeliveredCount = stockDao.getOrderOutCount(productId, res.getShopId(), storageId) + stockDao.getOrderOutTurn2FbaCount(productId, res.getShopId(), storageId);
                    int count = itemsDo.getCount();
                    if (stockRecordDo.getCanSellCount() - noDeliveredCount < count) {//优先仓库有库存，优先仓库发货
                        continue kk;
                    }
                }
                //
                storageId = storageDo.getId();
            }
            //默认仓库先捆包
            for (OrderOutputProductAddReq itemsDo : itemAddReqList) {
                Long productId = itemsDo.getProductId();
                if (productId == null) {
                    throw new BizException(SysConstant.OrderYahoo_Product_Notfound, orderYahooDo.getOrderId(), itemsDo.getCommoditySku());
                }
                stateId = mRegionService.getStateIdByPostCode(orderYahooDo.getShipZipCode());
                if (storageId != 0) {//大阪地区优先发货仓库
                } else if (stateId <= 8) {//大阪地区优先发货仓库
                    storageId = 12L;
                } else {//东京仓库优先发货仓库
                    storageId = 10L;
                }
                LambdaQueryWrapper<StockRecordDo> wrapper1 = new LambdaQueryWrapper();
                wrapper1.eq(StockRecordDo::getShopId, res.getShopId()).eq(StockRecordDo::getProductInfoId, productId).eq(StockRecordDo::getStorageId, storageId);
                StockRecordDo stockRecordDo = stockDao.selectOne(wrapper1);
                if (stockRecordDo == null) {
                    failedItems.add(itemsDo);
                    continue;
                }
                int noDeliveredCount = stockDao.getOrderOutCount(productId, res.getShopId(), storageId) + stockDao.getOrderOutTurn2FbaCount(productId, res.getShopId(), storageId);
                int count = itemsDo.getCount();
                if (stockRecordDo.getCanSellCount() - noDeliveredCount < count) {//优先仓库有库存，优先仓库发货
                    failedItems.add(itemsDo);
                    continue;
                }
                OrderOutputProductAddReq productDetail = new OrderOutputProductAddReq();
                productDetail.setOrderId(itemsDo.getOrderId());
                productDetail.setProductId(productId);
                productDetail.setCount(count);
                orderOutputProductDetailList.add(productDetail);
            }
            OrderOutputPackageAddReq packageDetail = new OrderOutputPackageAddReq();
            List<OrderOutputPackageAddReq> packageAddReqList = new ArrayList<>();
            packageDetail.setProductList(orderOutputProductDetailList);
            OrderOutputAddReq addReq = new OrderOutputAddReq();
            BeanUtils.copyProperties(res, addReq);
            packageAddReqList.add(packageDetail);
            addReq.setStorageId(storageId);
            addReq.setPackageList(packageAddReqList);
            //默认仓库库存不足
//                if (failedItems.size() != itemsDoList.size() && storageId != 0) {
            if (failedItems.size() < 1 && storageId != 0) {
                resList.add(addReq);
            } else {
                failedItems = itemAddReqList;
            } //一个仓库是否发完所有订单
            if (failedItems.size() > 0) {
                List<OrderOutputProductAddReq> productAddList = new ArrayList<>();
                //剩余一件商品无库存
                if (failedItems.size() == 1 && failedItems.get(0).getCount() == 1) {
                    storageId = 0L;
                    Long productId = failedItems.get(0).getProductId();
                    List<StorageDo> storageDos = storageDao.selectList(null);
                    int count = failedItems.get(0).getCount();
                    for (StorageDo storageDo : storageDos) {//遍历仓库是否都有库存
                        LambdaQueryWrapper<StockRecordDo> wrapper2 = new LambdaQueryWrapper();
                        wrapper2.eq(StockRecordDo::getShopId, res.getShopId()).eq(StockRecordDo::getProductInfoId, productId).eq(StockRecordDo::getStorageId, storageDo.getId());
                        StockRecordDo stockRecordDo1 = stockDao.selectOne(wrapper2);
                        size = shipPriceService.countSameSkuSize(new double[4], productId, count);
                        int noDeliveredCount1 = stockDao.getOrderOutCount(productId, res.getShopId(), storageDo.getId()) + stockDao.getOrderOutTurn2FbaCount(productId, res.getShopId(), storageDo.getId());
                        if (stockRecordDo1 != null && stockRecordDo1.getCanSellCount() - noDeliveredCount1 >= count) {
                            List<ShipPriceDo> shipPriceDos = shipPriceService.queryByRegionAndSize(res.getPostCode(), size[3], size[0] + size[1] + size[2], size[0], size[1], size[2], res.getCod(), res.getShipmentType(), storageDo.getId(), 1);
                            if (shipPriceDos.size() < 1 || shipPriceDos.get(0).getPrice() == 0) continue;
                            if (shipPirce > shipPriceDos.get(0).getPrice()) {//选择最便宜的价格
                                shipPirce = shipPriceDos.get(0).getPrice();
                                storageId = storageDo.getId();
                            }
                        }
                    }
                    OrderOutputProductAddReq productDetail = new OrderOutputProductAddReq();
                    productDetail.setProductId(productId);
                    productDetail.setCount(count);
                    productAddList.add(productDetail);
                    OrderOutputPackageAddReq packageDetail1 = new OrderOutputPackageAddReq();
                    if (storageId != 0) {
                        List<OrderOutputPackageAddReq> packageAddReqList1 = new ArrayList<>();
                        packageDetail1.setProductList(productAddList);
                        OrderOutputAddReq addReq1 = new OrderOutputAddReq();
                        BeanUtils.copyProperties(res, addReq1);
                        packageAddReqList1.add(packageDetail1);
                        addReq1.setStorageId(storageId);
                        addReq1.setPackageList(packageAddReqList1);
                        resList.add(addReq1);
                    } else {
                        throw new BizException(SysConstant.OrderYahoo_Stock_NotEnough, orderYahooDo.getOrderId(), failedItems.get(0).getCommoditySku());
                    }
                } else {
                    List<OrderOutputProductAddReq> productAddList1 = new ArrayList<>();
                    //多件商品无库存，第二优先捆包
                    List<OrderOutputProductAddReq> productDoListFailed = new ArrayList<>();
                    List<OrderOutputProductAddReq> productDoListSuccess = new ArrayList<>();
                    LambdaQueryWrapper<StorageDo> lambdaQueryWrapper = new LambdaQueryWrapper();
                    lambdaQueryWrapper.eq(StorageDo::getSupportShip, 1).ne(StorageDo::getId, storageId);
                    if (stateId <= 8) {
                        lambdaQueryWrapper.orderByDesc(StorageDo::getStorageArea);
                    } else {
                        lambdaQueryWrapper.orderByAsc(StorageDo::getStorageArea);
                    }
                    List<StorageDo> storageDos = storageDao.selectList(lambdaQueryWrapper);
                    storageId = 0L;
                    if (storageDos != null) {
                        kk:
                        for (StorageDo storageDo : storageDos) {
                            ;//遍历支持捆包仓库是否都有库存
                            for (OrderOutputProductAddReq productDo : failedItems) {
                                Long productId = productDo.getProductId();
                                int count = productDo.getCount();
                                LambdaQueryWrapper<StockRecordDo> wrapper1 = new LambdaQueryWrapper();
                                wrapper1.eq(StockRecordDo::getShopId, res.getShopId()).eq(StockRecordDo::getProductInfoId, productId).eq(StockRecordDo::getStorageId, storageDo.getId());
                                StockRecordDo stockRecordDo = stockDao.selectOne(wrapper1);
                                if (stockRecordDo == null) {
                                    productDoListSuccess.clear();
                                    productDoListFailed.clear();
                                    productDoListFailed.addAll(failedItems);
                                    continue kk;
                                }
                                int noDeliveredCount = stockDao.getOrderOutCount(productId, res.getShopId(), storageDo.getId()) + stockDao.getOrderOutTurn2FbaCount(productId, res.getShopId(), storageDo.getId());
                                if (stockRecordDo.getCanSellCount() - noDeliveredCount < count) {
                                    productDoListSuccess.clear();
                                    productDoListFailed.clear();
                                    productDoListFailed.addAll(failedItems);
                                    continue kk;
                                } else {
                                    productDoListSuccess.add(productDo);
                                }
                                if (storageId != 0 && storageId != storageDo.getId()) {
                                    productAddList1.clear();
                                    productDoListSuccess.clear();
                                    productDoListFailed.clear();
                                }
                                storageId = storageDo.getId();
                                OrderOutputProductAddReq productDetail = new OrderOutputProductAddReq();
                                productDetail.setProductId(productId);
                                productDetail.setCount(count);
                                productAddList1.add(productDetail);
                            }
                            if (productDoListSuccess.size() == failedItems.size()) {
                                productDoListSuccess.clear();
                                productDoListFailed.clear();
                                packageDetail = new OrderOutputPackageAddReq();
                                List<OrderOutputPackageAddReq> packageAddReqList1 = new ArrayList<>();
                                packageDetail.setProductList(productAddList1);
                                OrderOutputAddReq addReq1 = new OrderOutputAddReq();
                                BeanUtils.copyProperties(res, addReq1);
                                packageAddReqList1.add(packageDetail);
                                if (storageId != 0) {
                                    addReq1.setStorageId(storageId);
                                    addReq1.setPackageList(packageAddReqList1);
                                    resList.add(addReq1);
                                    break kk;
                                }
                            } else {
                                productDoListSuccess.clear();
                                productDoListFailed.addAll(failedItems);
                                continue kk;
                            }
                        }
                    } else {
                        productDoListFailed.addAll(failedItems);
                    }
                    List<OrderOutputProductAddReq> productAddList2 = new ArrayList<>();
                    //所有捆包仓库无库存的产品
                    if (productDoListFailed.size() > 0) {//捆包仓库无库存，分别发
                        LambdaQueryWrapper<StorageDo> queryWrapper = new LambdaQueryWrapper();
                        queryWrapper.eq(StorageDo::getCountryType, 1);
                        List<StorageDo> storageDoList = storageDao.selectList(queryWrapper);
                        for (OrderOutputProductAddReq productDo : productDoListFailed) {
                            storageId = 0L;
                            shipPirce = 99999D;
                            Long productId = productDo.getProductId();
                            int count = productDo.getCount();
                            for (StorageDo storageDo : storageDoList) {//遍历仓库是否都有库存
                                LambdaQueryWrapper<StockRecordDo> wrapper2 = new LambdaQueryWrapper();
                                size = shipPriceService.countSameSkuSize(new double[4], productId, 1);
                                wrapper2.eq(StockRecordDo::getShopId, res.getShopId()).eq(StockRecordDo::getProductInfoId, productId).eq(StockRecordDo::getStorageId, storageDo.getId());
                                StockRecordDo stockRecordDo1 = stockDao.selectOne(wrapper2);
                                int noDeliveredCount1 = stockDao.getOrderOutCount(productId, res.getShopId(), storageDo.getId()) + stockDao.getOrderOutTurn2FbaCount(productId, res.getShopId(), storageDo.getId());
                                if (stockRecordDo1 != null && stockRecordDo1.getCanSellCount() - noDeliveredCount1 >= count) {
                                    List<ShipPriceDo> shipPriceDos = shipPriceService.queryByRegionAndSize(res.getPostCode(), size[3], size[0] + size[1] + size[2], size[0], size[1], size[2], res.getCod(), res.getShipmentType(), storageDo.getId(), 1);
                                    if (shipPriceDos.size() < 1 || shipPriceDos.get(0).getPrice() == 0) continue;
                                    if (shipPirce > shipPriceDos.get(0).getPrice()) {//选择最便宜的价格
                                        shipPirce = shipPriceDos.get(0).getPrice();
                                        storageId = storageDo.getId();
                                    }
                                }
                            }
                            if (storageId != 0) {
                                OrderOutputProductAddReq productDetail = new OrderOutputProductAddReq();
                                productAddList2 = new ArrayList<>();
                                productDetail.setProductId(productId);
                                productDetail.setCount(count);
                                productAddList2.add(productDetail);
                                packageDetail = new OrderOutputPackageAddReq();
                                packageAddReqList = new ArrayList<>();
                                packageDetail.setProductList(productAddList2);
                                addReq = new OrderOutputAddReq();
                                BeanUtils.copyProperties(res, addReq);
                                packageAddReqList.add(packageDetail);
                                addReq.setStorageId(storageId);
                                addReq.setPackageList(packageAddReqList);
//                                if (orderCount > 0) addReq.setOrderNo(addReq.getOrderNo() + "-" + orderCount);
//                                orderCount++;
                                resList.add(addReq);
                            } else {
                                //剩余SKU都没有库存
                                throw new BizException(SysConstant.OrderYahoo_Stock_NotEnough, orderYahooDo.getOrderId(), failedItems.get(0).getCommoditySku());
                            }
                        }
                    }
                }
            }
        }
        if (resList.size() > 0) {
            operateRecordDao.operateAddRecord(SysConstant.OPERATE_CLICK_SEND,Long.parseLong(orderid),currentUserId,5);
        }
        return resList;
    }

    private String getAddress(String shipAddress1, String shipAddress2) {
        String address = shipAddress1;
        if (shipAddress1 == null) {
            address = shipAddress2;
        } else if (shipAddress2 == null) {
            address = shipAddress2;
        } else {
            address = shipAddress1 + shipAddress2;
        }
        return address;
    }

    @Override
    public SingleResult queryOrder2SendOutNoPackage(String orderid, Long currentUserId, boolean b, Long companyId) {
        return null;
    }

    @Override
    public SingleResult sendOutMatch(List<OrderOutputAddReq> resList, Long userId, Long companyId) {
        List<String> failOrders = new ArrayList<>();
        failOrders.addAll(orderOutputService.addYahooList(resList, userId));
        if (failOrders.size() > 0) {
//            return SingleResult.failure("300", String.format("成功导出%d个发货单", resList.size() - failOrders.size()), failOrders);
            return SingleResult.failure("300", SysConstant.OrderYahoo_Export_Success, failOrders, resList.size() - failOrders.size());
        } else {
            return SingleResult.success(failOrders);
        }
    }


    @Override
    public int setOrderSend(Long[] orderids, Long userId) {
        int count = baseMapper.updateOrderSend(orderids);
        for (Long orderid : orderids) {
            operateRecordDao.operateAddRecord(SysConstant.OPERATE_MARK_SEND,orderid,userId,5);
//            operateRecord("标记为发货", orderid, userId);

        }
        return count;
    }

//    private void operateRecord(String str, Long orderRakutenId, Long userId) {
//        OperateRecordDo operateRecordDo = new OperateRecordDo();
//        operateRecordDo.setDeleteFlag(0);
//        operateRecordDo.setThirdId(orderRakutenId);
//        operateRecordDo.setType(5);
//        operateRecordDo.setOperateBy(userId);
//        operateRecordDo.setOperateTime(new Date());
//        operateRecordDo.setContent(str);
//        operateRecordDao.insert(operateRecordDo);
//    }


    @Override
    public boolean setOrderSysTips(Long orderId, String desc, Long companyId) {
        OrderYahooDo orderYahooDo = dao.selectById(orderId);
        orderYahooDo.setSystemMemo(desc);
        updateById(orderYahooDo);
        return true;
    }

    /**
     * yahoo 获取订单列表 日期传中国时间， 内部转成日本时间
     *
     * @param shopId
     * @param map
     * @return
     */
    @Override
    public Map<String, Object> getYahooOrderList(Long shopId, Map<String, String> map) {
        String from = map.get("orderTimeFrom");
        String to = map.get("orderTimeTo");

        Date orderDateTo = StringUtils.isBlank(to) ? new Date() : DateUtils.stringFormatToDate(to, "yyyy-MM-dd HH:mm:ss");
        Date orderDateFrom = StringUtils.isBlank(from) ? DateUtils.passingDate(orderDateTo, -3) : DateUtils.stringFormatToDate(from, "yyyy-MM-dd HH:mm:ss");

//        orderDateTo = TimeUtils.formatDateToDate(orderDateTo, "yyyy-MM-dd HH:mm:ss", "Asia/Tokyo");//转成日本时间
//        orderDateFrom = TimeUtils.formatDateToDate(orderDateFrom, "yyyy-MM-dd HH:mm:ss", "Asia/Tokyo");//转成日本时间

        Map<String, Object> result = new HashMap<>();

        ShopDo shopDo = shopDao.selectById(shopId);
        if (shopDo == null || StringUtils.isBlank(shopDo.getYahooSellerId())) {
            result.put("code", "FAIL");
            result.put("msg", "Yahoo店铺没有sellerId");
            return result;
        }
        //todo 参数格式是 xml格式
        String field = "OrderId,Version,OriginalOrderId,ParentOrderId,DeviceType,IsSeen,IsSplit,IsRoyalty," +
                "RoyaltyFixTime,IsSeller,IsRatingB2s,OrderTime,ReleaseDate,LastUpdateTime,Suspect,OrderStatus," +
                "StoreStatus,PayStatus,SettleStatus,PayType,PayMethod,PayMethodName,PayDate,SettleId,BillFirstName," +
                "BillLastName,BillPrefecture,ShipStatus,ShipMethod,ShipMethodName,ShipRequestDate,ShipRequestTime,ShipNotes," +
                "ShipCompanyCode,ReceiveShopCode,ShipInvoiceNumber1,ShipInvoiceNumber2,ShipInvoiceNumberEmptyReason,ShipUrl," +
                "ArriveType,ShipDate,ShipFirstName,ShipLastName,ShipPrefecture,PayCharge,PayCharge,GiftWrapCharge," +
                "Discount,UsePoint,TotalPrice,RefundTotalPrice,sellerId,PayNo,ArrivalDate,printBillFlag";///Req/Search/Field

        int Result = 2000;   ///Req/Search/Result
        int Start = 1;       ///Req/Search/Start
        String Sort = "+order_time";///Req/Search/Sort
        String sellerId = shopDo.getYahooSellerId();///Req/SellerId
        //还有一个/Req/Search/Condition/

        //* 1需要 OrderID 或 OrderTime YYYYMMDDHH24MISS。
        //* 2如果未指定 OrderID，则需要 OrderTime、OrderTimeFrom、OrderTimeTo、PublicationTimeFrom 和 PublicationTimeTo 之一。
        //* 3指定以逗号分隔的多个匹配项。


        int total = 0;

        Set<String> orderIdList = new TreeSet<>();
        do {
            String body = null;
            //拼接参数 并且 转成日本时间
            String xmlParam = this.getYahooOrderListParam(Result, Start, orderDateFrom, orderDateTo, map.get("orderId"), field, sellerId);
            try {
                body = YahooUtils.yahooDoPost("https://circus.shopping.yahooapis.jp/ShoppingWebService/V1/orderList", getYahooUserAccessToken(shopId), xmlParam);
                Start += Result;
            } catch (Exception e) {
                e.printStackTrace();
            }
            if (StringUtils.isBlank(body)) {
                result.put("code", "FAIL");
                result.put("msg", "连接超时");
                return result;
            }

            //<?xml version='1.0' encoding='UTF-8' ?>
            //<Error>
            //<Message>AccessToken has been expired. This API session is shorter than another API.</Message>
            //<Code>px-04102</Code>
            //</Error>

            List<OrderYahooEntity> list = null;
            try {
                JSONObject object = XmlUtils.xml2Json(body);
                if (object == null) {
                    result.put("code", "FAIL");
                    result.put("msg", "Yahoo 获取订单列表 xml格式解析空指针");
                    return result;
                } else if (StringUtils.isNotBlank(object.getString("Error"))) {
                    result.put("code", "FAIL");
                    result.put("msg", object.getJSONObject("Error").getString("Message"));
                    return result;
                } else {
                    total = object.getJSONObject("Result").getJSONArray("Search").getJSONObject(0).getInteger("TotalCount");
                    list = JSONArray.parseArray(object.getJSONObject("Result").getJSONArray("Search").getJSONObject(0).getString("OrderInfo"), OrderYahooEntity.class);
                }

            } catch (JDOMException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            }

            if (list == null) {
                result.put("code", "FAIL");
                result.put("msg", "Yahoo 获取订单列表 xml格式解析 数组null");
                return result;
            }
            ///Result/Error/Message
//            List<OrderYahooEntity> list = JSONArray.parseArray(body, OrderYahooEntity.class);
            for (OrderYahooEntity entity : list) {
                if ("0".equals(entity.getPayStatus()) && "0".equals(entity.getShipStatus())) {
                    //未付款的 不可发货状态的订单，不保存
                    continue;
                }
                orderIdList.add(entity.getOrderId());
                OrderYahooDo et = dao.selectOne(new LambdaQueryWrapper<OrderYahooDo>()
                        .eq(OrderYahooDo::getOrderId, entity.getOrderId()).last(" order by id desc limit 1"));
                if (et == null) {
                    et = new OrderYahooDo();
                }

                BeanUtils.copyProperties(entity, et);
                et.setShopId(shopId);
                et.setCompanyId(shopDo.getCompanyId());
                if (StringUtils.isNotBlank(entity.getOrderTime()))
                    et.setOrderTime(DateUtils.stringFormatToDate(entity.getOrderTime(), "yyyy-MM-dd'T'hh:mm:ss"));
                if (StringUtils.isNotBlank(entity.getLastUpdateTime()))
                    et.setLastUpdateTime(DateUtils.stringFormatToDate(entity.getLastUpdateTime(), "yyyy-MM-dd'T'HH:mm:ss"));
                if (StringUtils.isNotBlank(entity.getRoyaltyFixTime()))
                    et.setRoyaltyFixTime(DateUtils.stringFormatToDate(entity.getRoyaltyFixTime(), "yyyy-MM-dd'T'HH:mm:ss"));


                getOrderDetailInfo(shopDo.getId(), sellerId, et, et.getId());
            }
        } while (total > Result);

        result.put("code", "SUCCESS");
        return result;
    }

    private void getOrderDetailInfo(Long shopDoId, String sellerId, OrderYahooDo orderYahooDo, Long id) {
        //todo 参数格式是 xml格式
        String field = "OrderId,Version,ParentOrderId,BuyerComments,SellerComments,Notes,DeviceType,ShipZipCode,ShipPrefecture,ShipCity,ShipAddress1,ShipAddress2," +
                "ShipPhoneNumber,StoreStatus," +
                "BillLastName,BillPrefecture,ShipStatus,ShipMethod,ShipMethodName,ShipRequestDate,ShipRequestTime,ShipNotes,ArrivalDate," +
                "ShipCompanyCode,ReceiveShopCode,ShipInvoiceNumber1,ShipInvoiceNumber2,ShipInvoiceNumberEmptyReason,ShipUrl," +
                "LineId,ItemId,Title,SubCode,SubCodeOption,ItemOption,Inscription,IsUsed,ProductId,Quantity,PointAvailQuantity";///Req/Search/Field

        int total = 0;
        Map result = new HashMap();

        Set<String> orderIdList = new TreeSet<>();
        String body = null;
        //拼接参数 并且 转成日本时间
        String xmlParam = "<Req>" +
                "<Target>" +
                "<OrderId>" + orderYahooDo.getOrderId() + "</OrderId>" +
                "<Field>" + field + "</Field>" +
                "</Target>" +
                "<SellerId>" + sellerId + "</SellerId>" +
                "</Req>";
        try {
            body = YahooUtils.yahooDoPost("https://circus.shopping.yahooapis.jp/ShoppingWebService/V1/orderInfo", getYahooUserAccessToken(shopDoId), xmlParam);
        } catch (Exception e) {
            e.printStackTrace();
        }
        if (StringUtils.isBlank(body)) {
            result.put("code", "FAIL");
            result.put("msg", "连接超时");
            log.error("getOrderDetailInfo" + "msg" + "连接超时");
        }

        //<?xml version='1.0' encoding='UTF-8' ?>
        //<Error>
        //<Message>AccessToken has been expired. This API session is shorter than another API.</Message>
        //<Code>px-04102</Code>
        //</Error>

        OrderYahooEntity orderYahooEntity = null;
        try {
            JSONObject object = XmlUtils.xml2Json(body);
            if (object == null) {
                log.error("object == null");
            } else if (StringUtils.isNotBlank(object.getString("Error"))) {
                log.error(object.toJSONString());
            } else {
                JSONObject jsonObject = object.getJSONObject("ResultSet").getJSONArray("Result").getJSONObject(0);
                orderYahooEntity = JSONArray.parseObject(jsonObject.getJSONArray("OrderInfo").getString(0), OrderYahooEntity.class);
            }

        } catch (JDOMException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
        if (orderYahooEntity.getShip() != null && orderYahooEntity.getShip().size() > 0) {
            OrderYahooShipEntity ship = orderYahooEntity.getShip().get(0);
            orderYahooDo.setShipAddress1(ship.getShipAddress1());
            orderYahooDo.setShipAddress2(ship.getShipAddress2());
            orderYahooDo.setShipZipCode(ship.getShipZipCode());
            orderYahooDo.setShipPrefecture(ship.getShipPrefecture());
            orderYahooDo.setShipCity(ship.getShipCity());
            orderYahooDo.setShipPhoneNumber(ship.getShipPhoneNumber());
            //ShipStatus,ShipMethod,ShipMethodName,ShipRequestDate,ShipRequestTime,ShipNotes,ArrivalDate
            orderYahooDo.setShipStatus(ship.getShipStatus());
            orderYahooDo.setShipMethod(ship.getShipMethod());
            orderYahooDo.setShipMethodMame(ship.getShipMethodName());
            if (StringUtils.isNotBlank(ship.getShipRequestDate()))
                orderYahooDo.setShipRequestDate(DateUtils.stringFormatToDate(ship.getShipRequestDate()));
            if (StringUtils.isNotBlank(ship.getShipRequestTime()))
                orderYahooDo.setShipRequestTime(ship.getShipRequestTime());
            if (StringUtils.isNotBlank(ship.getShipDate()))
                orderYahooDo.setShipDate(DateUtils.stringFormatToDate(ship.getShipDate()));
            if (StringUtils.isNotBlank(ship.getArrivalDate()))
                orderYahooDo.setArrivalDate(DateUtils.stringFormatToDate(ship.getArrivalDate()));
            orderYahooDo.setShipNotes(ship.getShipNotes());
            //ShipCompanyCode,ReceiveShopCode,ShipInvoiceNumber1,ShipInvoiceNumber2,ShipInvoiceNumberEmptyReason,ShipUr
            orderYahooDo.setShipCompanyCode(ship.getShipCompanyCode());
            orderYahooDo.setShipInvoiceNumber1(ship.getShipInvoiceNumber1());
            orderYahooDo.setShipInvoiceNumber2(ship.getShipInvoiceNumber2());
            orderYahooDo.setShipUrl(ship.getShipUrl());

            orderYahooDo.setNotes(orderYahooEntity.getNotes());
            orderYahooDo.setBuyerComments(orderYahooEntity.getBuyerComments());
            orderYahooDo.setSellerComments(orderYahooEntity.getSellerComments());
            orderYahooDo.setStoreStatus(orderYahooEntity.getStoreStatus());
        }
        if (orderYahooDo.getId() == null) {
            orderYahooDo.setCreateTime(new Date());
            dao.insert(orderYahooDo);
        } else {
            orderYahooDo.setUpdateTime(new Date());
            dao.updateById(orderYahooDo);
        }
        ///Result/Error/Message
//            List<OrderYahooEntity> list = JSONArray.parseArray(body, OrderYahooEntity.class);
        for (OrderYahooItemEntity entity : orderYahooEntity.getItem()) {
            OrderYahooItemDo et = itemDao.selectOne(new LambdaQueryWrapper<OrderYahooItemDo>()
                    .eq(OrderYahooItemDo::getLineId, entity.getLineId())
                    .eq(OrderYahooItemDo::getOrderId, orderYahooDo.getId())
                    .last(" order by id desc limit 1"));
            if (et == null) {
                et = new OrderYahooItemDo();
            }
            BeanUtils.copyProperties(entity, et);
            et.setOrderId(orderYahooDo.getId());
            if (et.getId() == null) {
                et.setCreateTime(new Date());
                itemDao.insert(et);
            } else {
                et.setUpdateTime(new Date());
                itemDao.updateById(et);
            }

        }
    }
//

    public String getYahooOrderInfoParam(String orderId, String field, String sellerId) {
        StringBuilder builder = new StringBuilder("<Req><Target><OrderId>");
        builder.append(orderId).append("</OrderId>").append("<Field>").append(field).append("</Field>").append("</Target>").append("SellerId").append(sellerId).append("</SellerId>").append("</Req>");
        return builder.toString();
    }

    @Override
    public Map<String, Object> orderShipStatusChange(Map<Long, List<OrderShipStatusChangeReq>> reqMap) {
        Map<String, Object> result = new HashMap<>();
        for (Long shopId : reqMap.keySet()) {
            ShopDo shopDo = shopDao.selectById(shopId);
            if (shopDo == null || StringUtils.isBlank(shopDo.getYahooSellerId())) {
                result.put("code", "FAIL");
                result.put("msg", "Yahoo店铺没有sellerId");
                return result;
            }
            List<OrderShipStatusChangeReq> dataList = reqMap.get(shopId);
            for (OrderShipStatusChangeReq req : buildEqualsOrder(dataList)) {
                StringBuilder builder = new StringBuilder("<Req><Target><OrderId>");
                builder.append(req.getOrderId()).append("</OrderId>").append("<IsPointFix>").append(req.getIsPointFix()).append("</IsPointFix>");
                if (StringUtils.isNotBlank(req.getOperationUser())) {
                    builder.append("<OperationUser>").append(req.getOperationUser()).append("</OperationUser>");
                }
                builder.append("</Target><Order>").append("<Ship><ShipStatus>").append(req.getShipStatus()).append("</ShipStatus>");
                if (StringUtils.isNotBlank(req.getShipMethod())) {
                    builder.append("<ShipMethod>").append(req.getShipMethod()).append("</ShipMethod>");
                }
                if (StringUtils.isNotBlank(req.getShipNotes())) {
                    builder.append("<ShipNotes>").append(req.getShipNotes()).append("</ShipNotes>");
                }
                if (StringUtils.isNotBlank(req.getShipCompanyCode())) {
                    builder.append("<ShipCompanyCode>").append(req.getShipCompanyCode()).append("</ShipCompanyCode>");
                }
                if (StringUtils.isNotBlank(req.getShipInvoiceNumber1())) {
                    builder.append("<ShipInvoiceNumber1>").append(req.getShipInvoiceNumber1()).append("</ShipInvoiceNumber1>");
                }
                if (StringUtils.isNotBlank(req.getShipInvoiceNumber2())) {
                    builder.append("<ShipInvoiceNumber2>").append(req.getShipInvoiceNumber2()).append("</ShipInvoiceNumber2>");
                }
                if (StringUtils.isNotBlank(req.getShipUrl())) {
                    builder.append("<ShipUrl><![CDATA[").append(req.getShipUrl()).append("]]></ShipUrl>");
                }
                if (StringUtils.isNotBlank(req.getShipDate())) {
                    builder.append("<ShipDate>").append(req.getShipDate()).append("</ShipDate>");
                }
                if (StringUtils.isNotBlank(req.getArrivalDate())) {
                    builder.append("<ArrivalDate>").append(req.getArrivalDate()).append("</ArrivalDate>");
                }
                builder.append("</Ship></Order><SellerId>").append(shopDo.getYahooSellerId()).append("</SellerId></Req>");
                logger.info(builder.toString());
                String body = null;
                try {
                    body = YahooUtils.yahooDoPost("https://circus.shopping.yahooapis.jp/ShoppingWebService/V1/orderShipStatusChange", getYahooUserAccessToken(shopId), builder.toString());
                } catch (Exception e) {
                    e.printStackTrace();
                }
                logger.info(body);
                if (StringUtils.isBlank(body)) {
                    result.put("code", "FAIL");
                    result.put("msg", "连接超时");
                    return result;
                }
                updateOrderUploadExpress(req.getOrderId());
//                StringBuilder builderOrder = new StringBuilder("<Req><Target><OrderId>");
//                builderOrder.append(req.getOrderId()).append("</OrderId>").append("<IsPointFix>").append(req.getIsPointFix()).append("</IsPointFix>");
//                if (StringUtils.isNotBlank(req.getOperationUser())) {
//                    builderOrder.append("<OperationUser>").append(req.getOperationUser()).append("</OperationUser>");
//                }
//                builderOrder.append("</Target><Order>").append("<OrderStatus>").append("5").append("</OrderStatus>");
//                builderOrder.append("</Order><SellerId>").append(shopDo.getYahooSellerId()).append("</SellerId></Req>");
//                logger.info(builderOrder.toString());
//                String bodyOrder = null;
//                try {
//                    bodyOrder = YahooUtils.yahooDoPost("https://circus.shopping.yahooapis.jp/ShoppingWebService/V1/orderStatusChange", getYahooUserAccessToken(shopId), builderOrder.toString());
//                } catch (Exception e) {
//                    e.printStackTrace();
//                }
//                logger.info(bodyOrder);
//                if (StringUtils.isBlank(body)) {
//                    result.put("code", "FAIL");
//                    result.put("msg", "连接超时");
//                    return result;
//                }
//
//                JSONObject object = null;
//                try {
//                    object = XmlUtils.xml2Json(body);
//                    if (object == null) {
//                        result.put("code", "FAIL");
//                        result.put("msg", "Yahoo 获取订单详情 xml格式解析空指针");
//                    } else if (StringUtils.isNotBlank(object.getString("Error"))) {
//                        result.put("code", "FAIL");
//                        result.put("msg", object.getJSONObject("Error").getString("Message"));
//                    } else {
//                        String status = object.getJSONObject("ResultSet").getJSONArray("Result").getJSONObject(0).getString("Status");
//                        if ("OK".equals(status)) {
//                            result.put("code", "SUCCESS");
//                        } else {
//                            result.put("code", "FAIL");
//                            result.put("msg", "发货失败");
//                        }
//                    }
//                    updateOrderUploadExpress(req.getOrderId());
//                } catch (JDOMException e) {
//                    e.printStackTrace();
//                } catch (IOException e) {
//                    e.printStackTrace();
//                }
//            }
            }
        }

        //<!-- •サンプルXML-->
        //
        //<ResultSet totalResultsAvailable="1" totalResultsReturned="1" ok="1" ng="0">
        //    <Result>
        //        <Status>OK</Status>
        //    </Result>
        //</ResultSet>
        //
        //
        //<!-- •警告ありのサンプルXML-->
        //
        //<ResultSet totalResultsAvailable="1" totalResultsReturned="1" ok="1" ng="0">
        //    <Result>
        //        <Status>OK</Status>
        //        <Warning>
        //            <Code>od91113</Code>
        //            <Message></Message>
        //            <Detail></Detail>
        //        </Warning>
        //    </Result>
        //</ResultSet>
        ///Error	-	エラーレスポンスのすべてを含みます。
        ///Error/Code	string	エラーコード
        ///Error/Message	string	エラーメッセージ
        ///Error/Detail	-	エラー詳細（ある場合）
        ///Error/Detail/SettleCode	string	決済システムのエラーコード（APIエラーコードが「od91112」の場合）
        return result;
    }

    private List<OrderShipStatusChangeReq> buildEqualsOrder(List<OrderShipStatusChangeReq> dataList) {
        List<OrderShipStatusChangeReq> returnList = new ArrayList<>();
        dataList.stream().sorted(new Comparator<OrderShipStatusChangeReq>() {
            @Override
            public int compare(OrderShipStatusChangeReq o1, OrderShipStatusChangeReq o2) {
                return o1.getOrderId().compareTo(o2.getOrderId());
            }
        }).collect(Collectors.toList());
        String lastOrderId = "";
        for (OrderShipStatusChangeReq orderShipStatusChangeReq : dataList) {
            if (lastOrderId.equals(orderShipStatusChangeReq.getOrderId())) {
                if (returnList.get(returnList.size() - 1).getOrderId().equals(orderShipStatusChangeReq.getOrderId())) {
                    if (StringUtils.isBlank(returnList.get(returnList.size() - 1).getShipInvoiceNumber1())) {
                        returnList.get(returnList.size() - 1).setShipInvoiceNumber1(orderShipStatusChangeReq.getShipInvoiceNumber1());
                    } else if (StringUtils.isBlank(returnList.get(returnList.size() - 1).getShipInvoiceNumber2())) {
                        returnList.get(returnList.size() - 1).setShipInvoiceNumber2(orderShipStatusChangeReq.getShipInvoiceNumber1());
                    } else {
                        returnList.get(returnList.size() - 1).setShipNotes(
                                returnList.get(returnList.size() - 1).getShipNotes() + " " +
                                        orderShipStatusChangeReq.getShipInvoiceNumber1());
                    }
                }
            } else {
                returnList.add(orderShipStatusChangeReq);
            }
        }
        return returnList;
    }

}
